#include "acl_stdafx.hpp"
#ifndef ACL_PREPARE_COMPILE
#include "stdlib/log.hpp"
#include "stdlib/locker.hpp"
#include "connpool/connect_client.hpp"
#include "connpool/connect_pool.hpp"
#include <sstream>
#endif

namespace acl
{

connect_pool::connect_pool(const char* addr, size_t max, size_t idx /* = 0 */)
: alive_(true)
, delay_destroy_(false)
, last_dead_(0)
, conn_timeout_(30)
, rw_timeout_(30)
, idx_(idx)
, max_(max)
, count_(0)
, idle_ttl_(-1)
, last_check_(0)
, check_inter_(30)
, total_used_(0)
, current_used_(0)
, last_(0)
{
	retry_inter_ = 1;
	ACL_SAFE_STRNCPY(addr_, addr, sizeof(addr_));
}

const char* connect_pool::get_pool_info() {
	std::stringstream pool_nfo;

	pool_nfo <<
			"addr_"          << ": [" << addr_          << "]" <<  std::endl <<
			"idx_"           << ": [" << idx_           << "]" <<  std::endl <<
			"max_"           << ": [" << max_           << "]" <<  std::endl <<
			"count_"         << ": [" << count_         << "]" <<  std::endl <<
			"total_used_"    << ": [" << total_used_    << "]" <<  std::endl <<
			"current_used_"  << ": [" << current_used_  << "]" <<  std::endl <<
			"last_"          << ": [" << last_          << "]" <<  std::endl <<
			"alive_"         << ": [" << alive_         << "]" <<  std::endl <<
			"last_dead_"     << ": [" << last_dead_     << "]" <<  std::endl <<
			"retry_inter_"   << ": [" << retry_inter_   << "]" <<  std::endl <<
			"conn_timeout_"  << ": [" << conn_timeout_  << "]" <<  std::endl <<
			"rw_timeout_"    << ": [" << rw_timeout_    << "]" <<  std::endl <<
			"delay_destroy_" << ": [" << delay_destroy_ << "]" <<  std::endl <<
			"idle_ttl_"      << ": [" << idle_ttl_      << "]" <<  std::endl <<
			"last_check_"    << ": [" << last_check_    << "]" <<  std::endl <<
			"check_inter_"   << ": [" << check_inter_   << "]" <<  std::endl;

	return pool_nfo.str().c_str();
}

connect_pool::~connect_pool()
{
	std::list<connect_client*>::iterator it = pool_.begin();
	for (; it != pool_.end(); ++it)
		delete *it;
}

connect_pool& connect_pool::set_timeout(int conn_timeout, int rw_timeout)
{
	// 网络连接超时时间(秒)
	conn_timeout_ = conn_timeout;
	// 网络 IO 超时时间(秒)
	rw_timeout_ = rw_timeout;
	return *this;
}

connect_pool& connect_pool::set_idle_ttl(time_t ttl)
{
	// 空闲连接的生命周期
	idle_ttl_ = ttl;
	return *this;
}

connect_pool& connect_pool::set_retry_inter(int retry_inter)
{
	lock_.lock();
	// 不可用连接池对象再次被启用的时间间隔
	retry_inter_ = retry_inter;
	lock_.unlock();

	return *this;
}

connect_pool& connect_pool::set_check_inter(int n)
{
	// 检查空闲连接的时间间隔
	check_inter_ = n;
	return *this;
}

bool connect_pool::aliving()
{
	// XXX，虽然此处未加锁，但也应该不会有问题，因为下面的 peek() 过程会再次
	// 对 alive_ 加锁，以防止多线程操作时的冲突
	if (alive_)
		return true;

	time_t now = time(NULL);

	lock_.lock();
	if (retry_inter_ > 0 && now - last_dead_ >= retry_inter_)
	{
		alive_ = true;
		lock_.unlock();

		// 重置服务端连接状态，以便重试
		logger("reset server: %s", get_addr());
		return true;
	}

	lock_.unlock();
	return false;
}

connect_client* connect_pool::peek()
{
	lock_.lock();
	if (alive_ == false) {
		time_t now = time(NULL);
		if (retry_inter_ <= 0 || now - last_dead_ < retry_inter_) {
			// 尚不可用
			lock_.unlock();
			return NULL;
		}
		// 可用
		alive_ = true;

		// 重置服务端连接状态，以便重试
		logger("reset server: %s", get_addr());
	}

	connect_client* conn;

	std::list<connect_client*>::iterator it = pool_.begin();
	if (it != pool_.end()) {
		// 如果连接池中还有空闲的连接句柄(已经是建立过连接的句柄)，取出
		conn = *it;
		pool_.erase(it);
		total_used_++;
		current_used_++;

		lock_.unlock();
		return conn;
	} else if (max_ > 0 && count_ >= max_) {
		// 没有空闲的连接句柄，且当前连接数已经超过设置的最大连接数，报错退出
		logger_error("too many connections, max: %d, curr: %d,"
				" server: %s", (int ) max_, (int ) count_, addr_);
		lock_.unlock();
		return NULL;
	}

	// 将以下三个值预 +1
	count_++;
	total_used_++;
	current_used_++;

	lock_.unlock();

	// 调用虚函数的子类实现方法，创建新的数据库句柄
	conn = create_connect();
	// 在调用 open 之前先设置超时时间
	conn->set_timeout(conn_timeout_, rw_timeout_);
	// 调用子类方法打开数据库连接
	if (conn->open() == false) {
		lock_.lock();

		// 因为打开连接失败，所以还需将上面预 +1 的三个成员再 -1
		count_--;
		total_used_--;
		current_used_--;
#ifdef AUTO_SET_ALIVE
		alive_ = false;
		(void) time(&last_dead_);
#endif

		lock_.unlock();
		delete conn;
		return NULL;
	}

	conn->set_pool(this);

	return conn;
}

void connect_pool::put(connect_client* conn, bool keep /* = true */)
{
	time_t now = time(NULL);

	lock_.lock();

	// 检查是否设置了自销毁标志位
	if (delay_destroy_)
	{
		delete conn;
		count_--;

		if (count_ <= 0)
		{
			// 如果引用计数为 0 则自销毁
			lock_.unlock();
			delete this;
		}
		else
			lock_.unlock();
		return;
	}

	if (keep && alive_)
	{
		conn->set_when(now);

		// 将句柄放回连接池过程中做一些清理
		put_call_back(conn);

		// 将归还的连接放在链表首部，这样在调用释放过期连接
		// 时比较方便，有利于尽快将不忙的数据库连接关闭
		pool_.push_front(conn);
	}
	else
	{
		acl_assert(count_ > 0);
		delete conn;
		count_--;
	}

	if (idle_ttl_ >= 0 && now - last_check_ >= check_inter_)
	{
		// 按照设置的idle_ttl_,清理连接池中的空闲连接句柄
		(void) check_idle(idle_ttl_, false);
		(void) time(&last_check_);
	}
	lock_.unlock();
}

void connect_pool::set_delay_destroy()
{
	lock_.lock();
	delay_destroy_ = true;
	lock_.unlock();
}

void connect_pool::set_alive(bool yes /* true | false */)
{
	lock_.lock();
	alive_ = yes;
	if (yes == false)
		time(&last_dead_);
	lock_.unlock();
}

int connect_pool::check_idle(time_t ttl, bool exclusive /* = true */)
{
	if (ttl < 0)
		return 0;

	if (exclusive)
		lock_.lock();

	if (pool_.empty())
	{
		if (exclusive)
			lock_.unlock();
		return 0;
	}

	if (ttl == 0)
	{
		int   n = 0;
		std::list<connect_client*>::iterator it = pool_.begin();
		for (; it != pool_.end(); ++it)
		{
			delete *it;
			n++;
		};
		pool_.clear();
		count_ = 0;
		if (exclusive)
			lock_.unlock();
		return n;
	}

	int n = 0;
	time_t now = time(NULL), when;

	std::list<connect_client*>::iterator it, next;
	std::list<connect_client*>::reverse_iterator rit = pool_.rbegin();

	for (; rit != pool_.rend();)
	{
		it = --rit.base();
		when = (*it)->get_when();
		if (when <= 0)
		{
			++rit;
			continue;
		}

		if (now - when < ttl)
			break;

		delete *it;
		next = pool_.erase(it);
		rit = std::list<connect_client*>::reverse_iterator(next);

		n++;
		count_--;
	}

	if (exclusive)
		lock_.unlock();
	return n;
}

} // namespace acl
